package zlib

import (
	"errors"
	"math"
	"strings"
	"time"
)

const (
	OneMinSec  = 60
	OneHourSec = 3600
	OneDaySec  = 86400
	OneWeekSec = 7 * 86400

	OneMin  = time.Minute
	OneHour = time.Hour
	OneDay  = 24 * time.Hour
	OneWeek = 7 * 24 * time.Hour
)

var (
	// DefaultLayout template for format time
	DefaultTimeLayout = "2006-01-02 15:04:05"
)

// 获取当前的时间 - 字符串
func Now() string {
	return time.Now().Format(DefaultTimeLayout)
}

// 获取当前的时间 - Unix时间戳
func NowUnix() int64 {
	return time.Now().Unix()
}

// 获取当前的时间 - 毫秒级时间戳
func NowMilliUnix() int64 {
	return time.Now().UnixNano() / 1000000
}

// 获取当前的时间 - 纳秒级时间戳
func NowNanoUnix() int64 {
	return time.Now().UnixNano()
}
func GetTimeDate(_format string) (date string) {
	if len(_format) == 0 {
		_format = "YmdHisMS"
	}
	date = _format

	// 时区
	//timeZone, _ := time.LoadLocation(ServerInfo["timezone"])
	timeZone := time.FixedZone("CST", 8*3600) // 东八区

	timer := time.Now().In(timeZone)

	var year int64 = int64(timer.Year())
	var month int64 = int64(timer.Month())
	var day int64 = int64(timer.Day())
	var hour int64 = int64(timer.Hour())
	var minute int64 = int64(timer.Minute())
	var second int64 = int64(timer.Second())
	var week int64 = int64(timer.Weekday())
	var ms int64 = int64(timer.UnixNano() / 1e6)
	var ns int64 = int64(timer.UnixNano() / 1e9)
	msTmp := IntToString(int64(math.Floor(float64(ms / 1000))))
	nsTmp := IntToString(int64(math.Floor(float64(ns / 1000000))))

	var _year string
	var _month string
	var _day string
	var _hour string
	var _minute string
	var _second string
	var _week string // 英文星期
	var _Week string // 中文星期
	var _ms string   // 毫秒
	var _ns string   // 纳秒

	_year = IntToString(year)
	if month < 10 {
		_month = IntToString(month)
		_month = "0" + _month
	} else {
		_month = IntToString(month)
	}
	if day < 10 {
		_day = IntToString(day)
		_day = "0" + _day
	} else {
		_day = IntToString(day)
	}
	if hour < 10 {
		_hour = IntToString(hour)
		_hour = "0" + _hour
	} else {
		_hour = IntToString(hour)
	}
	if minute < 10 {
		_minute = IntToString(minute)
		_minute = "0" + _minute
	} else {
		_minute = IntToString(minute)
	}
	if second < 10 {
		_second = IntToString(second)
		_second = "0" + _second
	} else {
		_second = IntToString(second)
	}
	_week = IntToString(week)
	WeekZh := [...]string{"日", "一", "二", "三", "四", "五", "六"} // 默认从"日"开始
	_Week = WeekZh[week]
	_ms = strings.Replace(IntToString(ms), msTmp, "", -1)
	_ns = strings.Replace(IntToString(ns), nsTmp, "", -1)

	// 替换关键词
	date = strings.Replace(date, "MS", _ms, -1)
	date = strings.Replace(date, "NS", _ns, -1)
	date = strings.Replace(date, "Y", _year, -1)
	date = strings.Replace(date, "m", _month, -1)
	date = strings.Replace(date, "d", _day, -1)
	date = strings.Replace(date, "H", _hour, -1)
	date = strings.Replace(date, "i", _minute, -1)
	date = strings.Replace(date, "s", _second, -1)
	date = strings.Replace(date, "W", _Week, -1)
	date = strings.Replace(date, "w", _week, -1)

	return
}

// DateToTimeS 秒日期时间戳转时间戳，s
func DateToTimeS(_date string, format string) int64 {
	var date string
	if len(_date) == 0 { //给一个默认值
		date = GetTimeDate("YmdHis")
	} else {
		date = _date
	}

	var layout string
	if format == "YmdHis" || format == "" {
		layout = "20060102150405" // 转化所需内定模板
	} else if format == "Y-m-d H:i:s" {
		layout = "2006-01-02 15:04:05"
	} else if format == "Y年m月d日 H:i:s" {
		layout = "2006年01月02日 15:04:05"
	} else {
		layout = "20060102150405"
	}

	//日期转化为时间戳
	loc, _ := time.LoadLocation("Local") //获取时区
	tmp, _ := time.ParseInLocation(layout, date, loc)
	timestamp := tmp.Unix() //转化为时间戳 类型是int64

	return timestamp
}

func GetDatesBetweenDay(startDate string, endDate string, format string) (day int64) {
	// 日期转秒时间戳
	startTime := DateToTimeS(startDate, format)
	endTime := DateToTimeS(endDate, format)
	// 获取日期秒之差
	dayTime := endTime - startTime
	// 时分秒将被忽略，只取天的部分
	day = int64(math.Floor(float64(dayTime / (24 * 60 * 60))))
	return
}

// Sleep 延缓执行,秒.
func Sleep(t int64) {
	time.Sleep(time.Duration(t) * time.Second)
}

// Usleep 以指定的微秒数延迟执行.
func Usleep(t int64) {
	time.Sleep(time.Duration(t) * time.Microsecond)
}

// ServiceStartime 获取当前服务启动时间戳,秒.
func ServiceStartime() int64 {
	return kuptime.Unix()
}

// ServiceUptime 获取当前服务运行时间,纳秒int64.
func ServiceUptime() time.Duration {
	return time.Since(kuptime)
}

func IsDate2time(str string) (bool, int64) {
	if str == "" {
		return false, 0
	} else if strings.ContainsRune(str, '/') {
		str = strings.Replace(str, "/", "-", -1)
	}

	chk := RegDatetime.MatchString(str)
	if !chk {
		return false, 0
	}

	leng := len(str)
	if leng < 19 {
		reference := "1970-01-01 00:00:00"
		str = str + reference[leng:19]
	}

	tim, err := Str2Timestamp(str)
	if err != nil {
		return false, 0
	}

	return true, tim
}

// Str2Timestamp 将字符串转换为时间戳,秒.
// str 为要转换的字符串;
// format 为该字符串的格式,默认为"2006-01-02 15:04:05" .
func Str2Timestamp(str string, format ...string) (int64, error) {
	tim, err := Str2Timestruct(str, format...)
	if err != nil {
		return 0, err
	}

	return tim.Unix(), nil
}

// Str2Timestruct 将字符串转换为时间结构.
// str 为要转换的字符串;
// format 为该字符串的格式,默认为"2006-01-02 15:04:05" .
func Str2Timestruct(str string, format ...string) (time.Time, error) {
	var f string
	if len(format) > 0 {
		f = strings.Trim(format[0], " ")
	} else {
		f = "2006-01-02 15:04:05"
	}

	if len(str) != len(f) {
		return time.Now(), errors.New("[Str2Timestruct]`format error")
	}

	return time.ParseInLocation(f, str, kuptime.Location())
}

// Format use default layout
func Format(t time.Time) string {
	return t.Format(DefaultTimeLayout)
}

// FormatBy given default layout
func FormatBy(t time.Time, layout string) string {
	return t.Format(layout)
}

// FormatUnix time seconds use default layout
func FormatUnix(sec int64) string {
	return time.Unix(sec, 0).Format(DefaultTimeLayout)
}

// FormatUnixBy format time seconds use given layout
func FormatUnixBy(sec int64, layout string) string {
	return time.Unix(sec, 0).Format(layout)
}

// NowAddDay add some day time from now
func NowAddDay(day int) time.Time {
	return time.Now().AddDate(0, 0, day)
}

// NowAddHour add some hour time from now
func NowAddHour(hour int) time.Time {
	return time.Now().Add(time.Duration(hour) * OneHour)
}

// NowAddMinutes add some minutes time from now
func NowAddMinutes(minutes int) time.Time {
	return time.Now().Add(time.Duration(minutes) * OneMin)
}

// NowAddSeconds add some seconds time from now
func NowAddSeconds(seconds int) time.Time {
	return time.Now().Add(time.Duration(seconds) * time.Second)
}

// AddYear add some year time for given time
func AddYear(t time.Time, year int) time.Time {
	return t.AddDate(year, 0, 0)
}

// AddMonth add some month time for given time
func AddMonth(t time.Time, month int) time.Time {
	return t.AddDate(0, month, 0)
}

// AddDay add some day time for given time
func AddDay(t time.Time, day int) time.Time {
	return t.AddDate(0, 0, day)
}

// AddHour add some hour time for given time
func AddHour(t time.Time, hour int) time.Time {
	return t.Add(time.Duration(hour) * OneHour)
}

// AddMinutes add some minutes time for given time
func AddMinutes(t time.Time, minutes int) time.Time {
	return t.Add(time.Duration(minutes) * OneMin)
}

// AddSeconds add some seconds time for given time
func AddSeconds(t time.Time, seconds int) time.Time {
	return t.Add(time.Duration(seconds) * time.Second)
}

// AddNanoseconds add some seconds time for given time
func AddNanoseconds(t time.Time, nanoSeconds int) time.Time {
	return t.Add(time.Duration(nanoSeconds) * time.Nanosecond)
}

// HourStart time for given time
func HourStart(t time.Time) time.Time {
	y, m, d := t.Date()
	return time.Date(y, m, d, t.Hour(), 0, 0, 0, t.Location())
}

// HourEnd time for given time
func HourEnd(t time.Time) time.Time {
	y, m, d := t.Date()
	return time.Date(y, m, d, t.Hour(), 59, 59, int(time.Second-time.Nanosecond), t.Location())
}

// DayStart time for given time
func DayStart(t time.Time) time.Time {
	y, m, d := t.Date()
	return time.Date(y, m, d, 0, 0, 0, 0, t.Location())
}

// DayEnd time for given time
func DayEnd(t time.Time) time.Time {
	y, m, d := t.Date()
	return time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), t.Location())
}

// YearStart time for given time
func YearStart(t time.Time) time.Time {
	y, _, _ := t.Date()
	return time.Date(y, 1, 1, 0, 0, 0, 0, t.Location())
}

// YearEnd time for given time
func YearEnd(t time.Time) time.Time {
	y, _, _ := t.Date()
	return time.Date(y, 1, 1, 23, 59, 59, int(time.Second-time.Nanosecond), t.Location())
}

// MonthStart time for given time
func MonthStart(t time.Time) time.Time {
	y, m, _ := t.Date()
	return time.Date(y, m, 1, 0, 0, 0, 0, t.Location())
}

// MonthEnd time for given time
func MonthEnd(t time.Time) time.Time {
	nextMonth := MonthStart(AddMonth(t, 1))

	return AddNanoseconds(nextMonth, -1)
}

// NowHourStart time
func NowHourStart() time.Time {
	return HourStart(time.Now())
}

// TodayStart time
func TodayStart() time.Time {
	return DayStart(time.Now())
}

// TodayEnd time
func TodayEnd() time.Time {
	return DayEnd(time.Now())
}

// ToLayout convert date template to go time layout
//
// Template Vars:
// 	Y,y - year
// 	 Y - year 2006
// 	 y - year 06
// 	M,m - month 01
// 	D,d - day 02
// 	H,h - hour 15
// 	I,i - minute 04
// 	S,s - second 05
//
func TimeConvertToLayout(template string) string {
	if template == "" {
		return DefaultTimeLayout
	}
	// layout eg: "2006-01-02 15:04:05"
	bts := make([]byte, 0, 24)
	for _, c := range StringToByte(template) {
		switch c {
		case 'Y':
			bts = append(bts, '2', '0', '0', '6')
		case 'y':
			bts = append(bts, '0', '6')
		case 'M', 'm':
			bts = append(bts, '0', '1')
		case 'D', 'd':
			bts = append(bts, '0', '2')
		case 'H', 'h':
			bts = append(bts, '1', '5')
		case 'I', 'i':
			bts = append(bts, '0', '4')
		case 'S', 's':
			bts = append(bts, '0', '5')
		default:
			bts = append(bts, c)
		}
	}

	return ByteToString(bts)
}
